﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace System.Peppers.Win32
{
    /// <summary>
    /// Class that is more lightweight than AutoResetEvent or ManualResetEvent
    /// </summary>
    public class LightResetEvent
    {
        private readonly object _lock = new object();
        private bool _set = false,
            _autoReset = false;

        /// <summary>
        /// Constructor, defaults to manual reset
        /// </summary>
        public LightResetEvent()
        { }

        /// <summary>
        /// Constructor, pass a true to make it auto reset
        /// </summary>
        /// <param name="autoReset">True to auto reset, false otherwise</param>
        public LightResetEvent(bool autoReset)
        {
            _autoReset = autoReset;
        }

        /// <summary>
        /// Constructor allowing auto/manual and a start value
        /// </summary>
        /// <param name="autoReset">True to auto reset, false otherwise</param>
        /// <param name="startValue">Starting value</param>
        public LightResetEvent(bool autoReset, bool startValue)
        {
            _autoReset = autoReset;
            _set = startValue;
        }

        /// <summary>
        /// Signals next thread
        /// </summary>
        public void Set()
        {
            lock (_lock)
            {
                if (!_autoReset)
                {
                    _set = true;
                }
                Monitor.Pulse(_lock);
            }
        }

        /// <summary>
        /// Resets threads to non-signalled
        /// </summary>
        public void Reset()
        {
            lock (_lock)
            {
                _set = false;
            }
        }

        /// <summary>
        /// Wait for a Set()
        /// </summary>
        /// <returns>True if success</returns>
        public bool WaitOne()
        {
            lock (_lock)
            {
                if (_set)
                {
                    return true;
                }
                return Monitor.Wait(_lock);
            }
        }

        /// <summary>
        /// Wait for a Set()
        /// </summary>
        /// <param name="millisecondsTimeout">Timeout to wait</param>
        /// <returns>True if success</returns>
        public bool WaitOne(int millisecondsTimeout)
        {
            lock (_lock)
            {
                if (_set)
                {
                    return true;
                }
                return Monitor.Wait(_lock, millisecondsTimeout);
            }
        }
    }
}
